// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/memory/weak_ptr.h"

namespace base {
namespace internal {

    WeakReference::Flag::Flag()
        : is_valid_(true)
    {
        // Flags only become bound when checked for validity, or invalidated,
        // so that we can check that later validity/invalidation operations on
        // the same Flag take place on the same sequenced thread.
        sequence_checker_.DetachFromSequence();
    }

    void WeakReference::Flag::Invalidate()
    {
        // The flag being invalidated with a single ref implies that there are no
        // weak pointers in existence. Allow deletion on other thread in this case.
        DCHECK(sequence_checker_.CalledOnValidSequence() || HasOneRef());
        //       << "WeakPtrs must be invalidated on the same sequenced thread.";
        is_valid_ = false;
    }

    bool WeakReference::Flag::IsValid() const
    {
        DCHECK(sequence_checker_.CalledOnValidSequence());
        //       << "WeakPtrs must be checked on the same sequenced thread.";
        return is_valid_;
    }

    WeakReference::Flag::~Flag()
    {
    }

    WeakReference::WeakReference()
    {
    }

    WeakReference::WeakReference(const Flag* flag)
        : flag_(flag)
    {
    }

    WeakReference::~WeakReference()
    {
    }

    WeakReference::WeakReference(WeakReference&& other)
    {
        this->flag_ = other.flag_;
    }

    WeakReference::WeakReference(const WeakReference& other)
    {
        this->flag_ = other.flag_;
    }

    // WeakReference::WeakReference(const WeakReference& other) = default;

    bool WeakReference::is_valid() const { return flag_.get() && flag_->IsValid(); }

    WeakReferenceOwner::WeakReferenceOwner()
    {
    }

    WeakReferenceOwner::~WeakReferenceOwner()
    {
        Invalidate();
    }

    WeakReference WeakReferenceOwner::GetRef() const
    {
        // If we hold the last reference to the Flag then create a new one.
        if (!HasRefs())
            flag_ = new WeakReference::Flag();

        return WeakReference(flag_.get());
    }

    void WeakReferenceOwner::Invalidate()
    {
        if (flag_.get()) {
            flag_->Invalidate();
            flag_ = NULL;
        }
    }

    WeakPtrBase::WeakPtrBase()
    {
    }

    WeakPtrBase::~WeakPtrBase()
    {
    }

    WeakPtrBase::WeakPtrBase(const WeakReference& ref)
        : ref_(ref)
    {
    }

} // namespace internal
} // namespace base
